package bsc.war.service;

import bsc.ejb.entity.Attachment;
import bsc.ejb.metadata.Framework;
import bsc.ejb.metadata.Icon;
import bsc.ejb.metadata.MapDrawing;
import com.sun.media.jai.codec.SeekableStream;
import java.awt.RenderingHints;
import java.awt.image.renderable.ParameterBlock;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.media.jai.JAI;
import javax.media.jai.OpImage;
import javax.media.jai.RenderedOp;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.log4j.Logger;
import org.springframework.util.FileCopyUtils;

/**
 *
 * @author memozac
 */
public class FileUtils {
   private static Logger logger = Logger.getLogger(FileUtils.class);
    
   public enum FileType{ATTACHMENT,MAP,ICON,LOGO};
   public static int FILE_MAX_SIZE = 8*1024*1024*4;
    
   public static final String FILE_ROOT_FOLDER= "c:\\jboss-4.2.2.GA\\server\\default\\deploy\\jboss-web.deployer\\files.war\\bsc";
   public static final String MAP_FOLDER = "\\map";
   public static final String ICON_FOLDER = "\\icon";
   public static final String LOGO_FOLDER = "\\logo";
   public static final String ATTACHMENT_FOLDER = "\\attachment";

   private static final String FILE_ROOT_URL = "/files/bsc";
   private static final String MAP_URL = "/map/";
   private static final String ICON_URL = "/icon/";
   private static final String ATTACHMENT_URL = "/attachment/";
   private static final String LOGO_URL = "/logo/";

   private static final String FILE_EXT = ".jpg";

   // The JAI.create action name for handling a stream.
   private static final String JAI_STREAM_ACTION = "stream";
   // The JAI.create action name for handling a resizing using a subsample averaging technique.
   private static final String JAI_SUBSAMPLE_AVERAGE_ACTION = "SubsampleAverage";
   // The JAI.create encoding format name for JPEG.
   private static final String JAI_ENCODE_FORMAT = "PNG";
   // The JAI.create action name for encoding image data.
   private static final String JAI_ENCODE_ACTION = "encode";

   public static int MAX_WIDTH_MAP = 725;
   public static int MAX_HEIGHT_MAP = 543;
   public static int MAX_WIDTH_LOGO = 240;
   public static int MAX_HEIGHT_LOGO = 80;
   public static int MAX_WIDTH_ICON = 48;
   public static int MAX_HEIGHT_ICON = 48;
    

   public static boolean saveFile(byte[] file,String fileName, FileType fileType){
        try {
            String path = FileUtils.FILE_ROOT_FOLDER;
            String uploadDir = path;
            // Create the directory if it doesn't exist
            File dirPath = new File(uploadDir);
            if (!dirPath.exists())dirPath.mkdirs();
            File uploadedFile;
            switch (fileType){
                case ATTACHMENT:
                    try {
                        uploadedFile = new File(FileUtils.generateFilePath(fileName,fileType));
                        FileCopyUtils.copy(file, uploadedFile);
                        return true;
                    } catch (Exception e) {return false;}
                case MAP:
                    try {
                        file = FileUtils.resizeImage(file,FileUtils.MAX_WIDTH_MAP,FileUtils.MAX_HEIGHT_MAP);
                        uploadedFile = new File(FileUtils.generateFilePath(fileName,fileType));
                        FileCopyUtils.copy(file, uploadedFile);
                        return true;
                    } catch (Exception e) {return false;}
                case ICON:
                    try {
                        file = FileUtils.resizeImage(file,FileUtils.MAX_WIDTH_ICON,FileUtils.MAX_HEIGHT_ICON);
                        uploadedFile = new File(FileUtils.generateFilePath(fileName,fileType));
                        FileCopyUtils.copy(file, uploadedFile);
                        return true;
                    } catch (Exception e) {return false;}
                case LOGO:
                    try {
                        file = FileUtils.resizeImage(file,FileUtils.MAX_WIDTH_LOGO,FileUtils.MAX_HEIGHT_LOGO);
                        uploadedFile = new File(FileUtils.generateFilePath(fileName,fileType));
                        FileCopyUtils.copy(file, uploadedFile);
                        return true;
                    } catch (Exception e) {e.printStackTrace();return false;}
                default:
                    return false;
            }
        } catch(Exception e){return false;}
    }

   private static String generateFilePath(String filename, FileType fileType){
        switch (fileType){
            case ATTACHMENT:
                return FILE_ROOT_FOLDER + ATTACHMENT_FOLDER + System.getProperty("file.separator")+filename;
            case MAP:
                return FILE_ROOT_FOLDER + MAP_FOLDER + System.getProperty("file.separator")+filename;
            case ICON:
                return FILE_ROOT_FOLDER + ICON_FOLDER + System.getProperty("file.separator")+filename;
            case LOGO:
                return FILE_ROOT_FOLDER + LOGO_FOLDER + System.getProperty("file.separator")+filename;
        }
        return null;
    }
   public static String generateFileURL(String filename, FileType fileType){
        switch (fileType){
            case ATTACHMENT:
                return FILE_ROOT_URL + ATTACHMENT_URL + filename;
            case MAP:
                return FILE_ROOT_URL + MAP_URL + filename;
            case ICON:
                return FILE_ROOT_URL + ICON_URL + filename;
            case LOGO:
                return FILE_ROOT_URL + LOGO_URL + filename;
        }
        return null;
    }

   public static String generateFilename(Object entity, FileType fileType){
        String baseName = null;
        switch (fileType){
            case ATTACHMENT:
                Attachment attachment = (Attachment)entity;
                baseName = "attach_" + attachment.getIdAttachment().toString();
                break;
            case MAP:
                MapDrawing mapDrawing = (MapDrawing)entity;
                baseName = "map_" + mapDrawing.getIdMapDrawing().toString() + FileUtils.FILE_EXT;
                break;
            case ICON:
                Icon icon = (Icon)entity;
                baseName = "icon_" + icon.getIdIcon().toString() + FileUtils.FILE_EXT;
            case LOGO:
                Framework framework = (Framework)entity;
                baseName = "logo_" + framework.getIdFramework().toString() + FileUtils.FILE_EXT;
        }
        return baseName;
    }

   public static boolean isImage(String filename){
        if(filename == null) return false;
        filename = filename.toUpperCase();
        return filename.endsWith(".PNG") || filename.endsWith(".GIF") || filename.endsWith(".JPG") || filename.endsWith(".JPEG") || filename.endsWith(".TIF") || filename.endsWith(".BMP") || filename.endsWith(".TIFF") || filename.endsWith(".JIF") || filename.endsWith(".JFIF") || filename.endsWith(".JP2") || filename.endsWith(".JPX") || filename.endsWith(".J2K") || filename.endsWith(".J2C");
    }
    
   //Resizes the image according to vertical proportion and horizontal when horizontal exceeds
   public static byte[] resizeImage(byte[] pImageData, int pMaxWidth, int pMaxHeight) throws Exception, IOException {
        byte[]resizedImageByteArray = resizeBasicImage(pImageData, pMaxWidth, 0);
        InputStream imageInputStream = new ByteArrayInputStream(resizedImageByteArray);
        // read in the original image from an input stream
        SeekableStream seekableImageStream = SeekableStream.wrapInputStream(imageInputStream, true);
        RenderedOp originalImage = JAI.create(JAI_STREAM_ACTION, seekableImageStream);
        ((OpImage) originalImage.getRendering()).setTileCache(null);
        // int origImageWidth = originalImage.getWidth();
        int origImageHeight = originalImage.getHeight();
        if(origImageHeight > pMaxHeight && pMaxHeight > 0) resizedImageByteArray = resizeImageByHeight(pImageData, 0,pMaxHeight);
        return resizedImageByteArray;
    }
    
   private static byte[] resizeBasicImage(byte[] pImageData, int pMaxWidth, int pMaxHeight) throws Exception, IOException {
        InputStream imageInputStream = new ByteArrayInputStream(pImageData);
        // read in the original image from an input stream
        SeekableStream seekableImageStream = SeekableStream.wrapInputStream(imageInputStream, true);
        RenderedOp originalImage = JAI.create(JAI_STREAM_ACTION, seekableImageStream);
        ((OpImage) originalImage.getRendering()).setTileCache(null);
        int origImageWidth = originalImage.getWidth();
        int origImageHeight = originalImage.getHeight();
        // now resize the image
        double scaleW = 1.0;
        double scaleH = -1;
        if (pMaxWidth > 0 && origImageWidth > pMaxWidth) {
            scaleW = (double) pMaxWidth / originalImage.getWidth();
        }
        if (pMaxHeight > 0 && origImageHeight > pMaxHeight) {
            scaleH = (double) pMaxWidth / originalImage.getHeight();
        }
        ParameterBlock paramBlock = new ParameterBlock();
        paramBlock.addSource(originalImage); // The source image
        paramBlock.add(scaleW); // The xScale
        paramBlock.add(scaleH==-1?scaleW:scaleH); // The yScale
        paramBlock.add(0.0); // The x translation
        paramBlock.add(0.0); // The y translation
        RenderingHints qualityHints = new RenderingHints(RenderingHints.KEY_RENDERING,RenderingHints.VALUE_RENDER_QUALITY);
        RenderedOp resizedImage = JAI.create(JAI_SUBSAMPLE_AVERAGE_ACTION, paramBlock, qualityHints);
        // lastly, write the newly-resized image to an output stream, in a specific encoding
        ByteArrayOutputStream encoderOutputStream = new ByteArrayOutputStream();
        JAI.create(JAI_ENCODE_ACTION, resizedImage, encoderOutputStream, JAI_ENCODE_FORMAT, null);
        // Export to Byte Array
        byte[] resizedImageByteArray = encoderOutputStream.toByteArray();
        return resizedImageByteArray;
    }

   //Resizes the image according to horizontal proportion
   private static byte[] resizeImageByHeight(byte[] pImageData, int pMaxWidth, int pMaxHeight) throws Exception, IOException {
        InputStream imageInputStream = new ByteArrayInputStream(pImageData);
        // read in the original image from an input stream
        SeekableStream seekableImageStream = SeekableStream.wrapInputStream(imageInputStream, true);
        RenderedOp originalImage = JAI.create(JAI_STREAM_ACTION, seekableImageStream);
        ((OpImage) originalImage.getRendering()).setTileCache(null);
        int origImageWidth = originalImage.getWidth();
        int origImageHeight = originalImage.getHeight();
        // now resize the image
        double scaleW = -1;
        double scaleH = 1;

        if (pMaxWidth > 0 && origImageWidth > pMaxWidth) {
            scaleW = (double) pMaxWidth / originalImage.getWidth();
        }
        if (pMaxHeight > 0 && origImageHeight > pMaxHeight) {
            scaleH = (double) pMaxHeight / originalImage.getHeight();
        }
        ParameterBlock paramBlock = new ParameterBlock();
        paramBlock.addSource(originalImage); // The source image
        paramBlock.add(scaleW==-1?scaleH:scaleW); // The xScale
        paramBlock.add(scaleH); // The yScale
        paramBlock.add(0.0); // The x translation
        paramBlock.add(0.0); // The y translation
        RenderingHints qualityHints = new RenderingHints(RenderingHints.KEY_RENDERING,
                RenderingHints.VALUE_RENDER_QUALITY);

        RenderedOp resizedImage = JAI.create(JAI_SUBSAMPLE_AVERAGE_ACTION, paramBlock, qualityHints);

        // lastly, write the newly-resized image to an output stream, in a specific encoding
        ByteArrayOutputStream encoderOutputStream = new ByteArrayOutputStream();
        JAI.create(JAI_ENCODE_ACTION, resizedImage, encoderOutputStream, JAI_ENCODE_FORMAT, null);
        // Export to Byte Array
        byte[] resizedImageByteArray = encoderOutputStream.toByteArray();
        return resizedImageByteArray;
    }

   public static Map<String,Object> getMultipartParameters(HttpServletRequest request){

        Map<String,Object> parameterValues = new HashMap<String,Object>();
        //List<byte[]> filesUploaded = new ArrayList<byte[]>();
        //List<FileItem> files = new ArrayList<FileItem>();  //Stores the files that have been added
        boolean isMultipart = ServletFileUpload.isMultipartContent(request);
        if(isMultipart) {
            FileItemFactory factory = new DiskFileItemFactory();
            ServletFileUpload upload = new ServletFileUpload(factory);
            upload.setSizeMax(FileUtils.FILE_MAX_SIZE);
            try {
                // Parse the request**********************************
                List<FileItem> fields = upload.parseRequest(request);
                // Iterates the files that have been added************
                Iterator<FileItem> it = fields.iterator();
                while (it.hasNext()) {
                    FileItem fileItem = it.next();
                    if (!fileItem.isFormField() && fileItem.getSize() > 0){
                        parameterValues.put(fileItem.getFieldName(), fileItem.get());
                        parameterValues.put(fileItem.getFieldName() + "_filename", fileItem.getName());
                    }else{
                     parameterValues.put(fileItem.getFieldName(), fileItem.getString());
                    }
                }//Ends while

               return parameterValues;
            } catch (FileUploadException e) {
                logger.error("FileUploadException" , e);
            }
        }//ends if is multipart
        return null;
    }








    /*
    public static byte[] getUploadedFile(HttpServletRequest request){
        byte[] fileUploaded = null;
        List<FileItem> files = new ArrayList<FileItem>();  //Stores the files that have been added
        if(ServletFileUpload.isMultipartContent(request)) {
            FileItemFactory factory = new DiskFileItemFactory();
            ServletFileUpload upload = new ServletFileUpload(factory);
            upload.setSizeMax(FileUtils.FILE_MAX_SIZE);
            try {
                // Parse the request**********************************
                List<FileItem> fields = upload.parseRequest(request);
                // Iterates the files that have been added************
                Iterator<FileItem> it = fields.iterator();
                while(it.hasNext()) {
                    FileItem fileItem = it.next();
                    if(!fileItem.isFormField() && fileItem.getSize() > 0) files.add(fileItem);

                }//Ends while
                for(FileItem fileItem : files) fileUploaded = fileItem.get();
                
                if(fileUploaded != null && fileUploaded.length > 0) return fileUploaded;

            } catch (FileUploadException e) {
                e.printStackTrace();
                logger.error("FileUploadException" , e);
            }
        }//ends if is multipart
        return null;
    }

    public static String getParameter(HttpServletRequest request, String parameter){
        if(ServletFileUpload.isMultipartContent(request)) {
            System.out.println("entra...");
            FileItemFactory factory = new DiskFileItemFactory();
            ServletFileUpload upload = new ServletFileUpload(factory);
            // upload.setSizeMax(FileUtils.FILE_MAX_SIZE);
            try{
                // Parse the request**********************************
                List<FileItem> fields = upload.parseRequest(request);
                // Iterates the files that have been added************
                Iterator<FileItem> it = fields.iterator();
                while (it.hasNext()) {
                    FileItem fileItem = it.next();
                    System.out.println("fileItem: "+fileItem);
                    System.out.println("fileItem.getFieldName: "+fileItem.getFieldName());
                    if(fileItem.getFieldName().equals(parameter)) return fileItem.getString();
                    
                }//Ends while

            }catch (FileUploadException e){
                e.printStackTrace();
                logger.error("FileUploadException" , e);
            }
        }//ends if is multipart
        return null;
    }
     */
}

